<?php
/**
 * +------------------------------
 * Created by PhpStorm.
 * +------------------------------
 * User: xxx
 * +------------------------------
 * DateTime: 2019/12/12 15:00
 * +------------------------------
 */

namespace Core\lib;

use Swoole\Coroutine\Channel;

/**
 * 自定义连接池
 * Class GenericPool
 * @package Core\pool
 */
class GenericPool
{
    /**
     * @var int pool size
     */
    private $size = 0;
    /**
     * @var callable construct a connection
     */
    private $factory = null;
    /**
     * @var Channel
     */
    private $channel = null;

    /**
     * GenericPool constructor.
     * @param $size
     * @param callable $factory
     * @throws \Exception
     */
    public function __construct($size, callable $factory)
    {
        $this->size = $size;
        $this->factory = $factory;
        $this->init();
    }

    /**
     * @throws \Exception
     */
    private function init()
    {
        if ($this->size <= 0) {
            throw new \Exception('The "size" property must be greater than zero.');
        }
        if (empty($this->factory)) {
            throw new \Exception('The "factory" property must be set.');
        }
        if (!is_callable($this->factory)) {
            throw new \Exception('The "factory" property must be callable.');
        }
        $this->bootstrap();
    }

    /**
     * bootstrap pool
     */
    private function bootstrap()
    {
        $this->channel = new Channel($this->size);
        for ($i = 0; $i < $this->size; $i++) {
            $this->channel->push(call_user_func($this->factory));
        }
    }

    /**
     * Acquire a connection
     * @param int $timeout
     * @return mixed
     */
    public function acquire($timeout = 0)
    {
        return $this->channel->pop($timeout);
    }

    /**
     * Release a resource
     * @param mixed $resource
     */
    public function release($resource)
    {
        $this->channel->push($resource);
    }
}

//==============================使用方法=======================================================

//暂时注释掉
/*
try {
    $pool = new GenericPool(10, function () {
        $connection = new \Swoole\Coroutine\MySQL();
        $connection->connect([
            'host' => '127.0.0.1',
            'port' => 3306,
            'user' => 'root',
            'password' => 'root',
            'database' => 'test',
        ]);
        if (!$connection->connected) {
            throw new \Exception($connection->connect_error, $connection->errno);
        }
        return $connection;
    });
} catch (\Exception $e) {
}


for ($i = 0; $i < 100; $i++) {
    go(function () use ($pool, $i) {

        //@var MySQL $connectio
        $connection = $pool->acquire();
        defer(function () use ($pool, $connection) {
            $pool->release($connection);
        });

        $data = $connection->query('SELECT CONNECTION_ID() AS `id`');
        print_r($data);
    });
}

*/